package main;

import java.util.HashMap;
import java.util.HashSet;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TravelAgent;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.potion.PotionEffect;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Scoreboard;

public class EventManager implements Listener {
	private final QUHC plugin;
	private final HashMap<String, WorldManager> worldManagers = new HashMap<String, WorldManager>();
	private final HashMap<String, PlayerInfo> playerInfo = new HashMap<String, PlayerInfo>();

	public EventManager(QUHC plugin) {
		this.plugin = plugin;
		Bukkit.getPluginManager().registerEvents(this, plugin);
	}
	
	private void removePlayer(Player player) {
		if (player.hasMetadata("QUHC")) {
			restorePlayer(player);
			player.removeMetadata("QUHC", plugin);
			WorldManager worldManager = worldManagers.get(player.getName());
			if (worldManager.getWorldIsEmpty()) {
				worldManager.deleteWorld();
			}
			worldManagers.remove(player.getName());
		}
	}

	public void start(HashSet<String> lobby) {
		Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
		scoreboard.registerNewObjective("health", "health");
		scoreboard.getObjective("health").setDisplaySlot(DisplaySlot.SIDEBAR);
		scoreboard.getObjective("health").setDisplayName("Health");
		
		WorldManager worldManager = new WorldManager(lobby);
		for (String name : lobby) {
			Player player = Bukkit.getPlayer(name);
			player.setMetadata("QUHC", new FixedMetadataValue(plugin, null));
			savePlayer(player);
			worldManagers.put(name, worldManager);
			player.setScoreboard(scoreboard);
			scoreboard.getObjective("health").getScore(player).setScore(20);
			player.sendMessage("Beginning a round of UHC!");
		}
	}

	public void quit() {
		for (String name : playerInfo.keySet()) {
			restorePlayer(Bukkit.getPlayer(name));
		}
		for (WorldManager worldManager : worldManagers.values()) {
			worldManager.deleteWorld();
		}
		playerInfo.clear();
		worldManagers.clear();
	}
	
	public void savePlayer(Player player) {
		playerInfo.put(player.getName(), new PlayerInfo(player));
		player.setHealth(20);
		player.setExp(0);
		player.setFoodLevel(20);
		player.setSaturation(20);
		player.getInventory().clear();
		player.getInventory().setArmorContents(null);	
		for (PotionEffect effect : player.getActivePotionEffects()) {
			player.removePotionEffect(effect.getType());
		}
	}

	public void restorePlayer(Player player) {
		playerInfo.get(player.getName()).restore();
		playerInfo.remove(player.getName());
		player.sendMessage("Round has ended");
	}
	
	@EventHandler
	private void healthRegen(EntityRegainHealthEvent event) {
		if (event.getEntity().hasMetadata("QUHC")) {
			if (event.getRegainReason().equals(RegainReason.REGEN) == false ||
					event.getRegainReason().equals(RegainReason.MAGIC_REGEN) == false) {
				event.setCancelled(true);
			}
		}
	}

	@EventHandler
	private void ghastTears(ItemSpawnEvent event) {
		if (event.getEntity().getItemStack().getType().equals(Material.GHAST_TEAR)) {
			event.getEntity().getItemStack().setType(Material.GOLD_INGOT);
		}
	}

	@EventHandler
	private void glisteningMelonOldCrafting(PrepareItemCraftEvent event) {
		if (event.getView().getPlayer().hasMetadata("QUHC")) {
			CraftingInventory inventory = event.getInventory();
			if (event.getRecipe().getResult().getType().equals(Material.SPECKLED_MELON)) {
				if (inventory.contains(Material.GOLD_NUGGET)) {
					inventory.setResult(null);
				}
			}
		}
		else {
			CraftingInventory inventory = event.getInventory();
			if (event.getRecipe().getResult().getType().equals(Material.SPECKLED_MELON)) {
				if (inventory.contains(Material.GOLD_BLOCK)) {
					inventory.setResult(null);
				}
			}
		}
	}

	@EventHandler
	private void playerRespawn(PlayerRespawnEvent event) {
		removePlayer(event.getPlayer());
	}
	
	@EventHandler
	private void winCondition(PlayerDeathEvent event) {
		Player player = event.getEntity();
		WorldManager worldManager = worldManagers.get(player.getName());
		World overworld = worldManager.getOverworld();
		World nether = worldManager.getNether();
		if ((overworld.getPlayers().size() + nether.getPlayers().size()) == 2) {
			for (Player winner : overworld.getPlayers()) {
				if (winner.isDead() == false) {
					winner.sendMessage("You have won this round of UHC!");
				}
			}
			for (Player winner : nether.getPlayers()) {
				if (winner.isDead() == false) {
					winner.sendMessage("You have won this round of UHC!");
				}
			}
		}
	}

	@EventHandler
	private void netherTravel(PlayerPortalEvent event) {
		if (event.getPlayer().hasMetadata("QUHC")) {
			Player player = event.getPlayer();
			WorldManager worldManager = worldManagers.get(player.getName());
			if (event.getFrom().getWorld().getEnvironment().equals(Environment.NORMAL)) {
				Location destination = event.getFrom();
				destination.setX(destination.getBlockX() / 8);
				destination.setZ(destination.getBlockZ() / 8);
				destination.setWorld(worldManager.getNether());
				event.setTo(event.getPortalTravelAgent().findOrCreate(destination));
			}
			else if (event.getFrom().getWorld().getEnvironment().equals(Environment.NETHER)) {
				Location destination = event.getFrom();
				destination.setX(destination.getBlockX() * 8);
				destination.setZ(destination.getBlockZ() * 8);
				destination.setWorld(worldManager.getOverworld());
				TravelAgent portal = event.getPortalTravelAgent();
				if (portal.findPortal(destination) != null) {
					event.setTo(portal.findPortal(destination));
				}
				else {
					int players = worldManager.getOverworld().getPlayers().size();
					players = players + worldManager.getNether().getPlayers().size();
					destination = worldManager.getOverworld().getSpawnLocation();
					double x = destination.getX() + 45 * players * Integer.signum(players);
					destination.setX(x);
					double z = destination.getZ() + 45 * players * Integer.signum(players);
					destination.setZ(z);
					event.setTo(portal.findOrCreate(destination));
				}
			}
		}
	}
}
